﻿#include "MyPicture.h"

MyPicture::MyPicture(const std::string& filename)
{
    if (!check_image_exist(filename))
        return;

    // 读取一张图片到 Mat 对象中
	my_image = cv::imread(ny_filename, cv::IMREAD_COLOR);

    // 检查图片是否成功读取
    if (my_image.empty()) {
        std::cout << "Could not open or find the image.\n";
        return;
    }

    // 尝试读取PNG图片，排查JPEG解码问题
    /*std::string pngTestPath = R"(D:\TestFace1.png)";
    cv::Mat pngImage = cv::imread(pngTestPath, cv::IMREAD_COLOR);
    if (!pngImage.empty()) {
        std::cout << "PNG 图片读取成功，JPEG 解码可能有问题。" << std::endl;
    }
    else {
        std::cout << "PNG图片也无法读取，可能是OpenCV库或环境问题。" << std::endl;
        return -1;
    }*/
}


MyPicture::~MyPicture()
{
    // 释放内存
    my_image.release();
}

void MyPicture::release_image()
{
    // 释放内存
    if (!my_image.empty())
        my_image.release();
}

bool MyPicture::check_image_exist(const std::string& filename)
{
    // 验证路径是否正确
    if (!fs::exists(filename)) {
        std::cout << "File does not exist: " << filename << std::endl;
        return false;
    }
    // 检查文件是否为常规文件或具有读权限
    if (!fs::is_regular_file(filename)) {
        std::cout << "File is not a regular file: " << filename << std::endl;
        return false;
    }
    fs::perms filePermissions = fs::status(filename).permissions();
    if ((filePermissions & fs::perms::owner_read) == fs::perms::none &&
        (filePermissions & fs::perms::group_read) == fs::perms::none &&
        (filePermissions & fs::perms::others_read) == fs::perms::none) {
        std::cout << "File is not a regular file or does not have read permissions: " << filename << std::endl;
        return false;
    }

    // 检查路径是否有 BOM 干扰（UTF-8带签名可能导致路径首字节为0xEF,0xBB,0xBF），并保存文件名
    if (!filename.empty() &&
        (static_cast<unsigned char>(filename[0]) == 0xEF)) {
        // 去除BOM
        ny_filename = filename.substr(3);
        std::cout << "[警告] 路径字符串检测到BOM，已自动去除。" << std::endl;
    }
    else
        ny_filename = filename;

    // 用 ifstream 测试文件能否打开，排除权限和编码问题
    std::ifstream testFile(ny_filename, std::ios::binary);
    if (!testFile.is_open()) {
        std::cout << "[错误] std::ifstream无法打开文件，可能是路径编码或权限问题: " << ny_filename << std::endl;
        return false;
    }
    testFile.close();

    std::cout << "Image path: " << ny_filename << std::endl;
    return true;
}

void MyPicture::load_image(const std::string& filename)
{
    if (filename.empty()) {
        std::cout << "Load image failed, empty filename.\n";
        return;
    }
    if (!check_image_exist(filename))
        return;
    // 释放原有图片
    release_image();

    // 加载图片
    my_image = cv::imread(filename, cv::IMREAD_COLOR);

    // 检查图片是否成功读取
    if (my_image.empty()) {
        std::cout << "Could not open or find the image.\n";
        return;
    }
}

void MyPicture::save_image(const std::string& filename)
{
    if (filename.empty()) {
        std::cout << "Save image failed, empty filename.\n";
        return;
    }
    if (my_image.empty()) {
        std::cout << "Save image failed, empty image.\n";
        return;
    }
    // 保存图片
    if (!cv::imwrite(filename, my_image)) {
        std::cout << "Could not save the image.\n";
        return;
    }
    std::cout << "Image saved to: " << filename << "successfully.\n";
}

void MyPicture::compress_image(const std::string& filename, int quality) {
    // 检查文件名是否为空
    if (filename.empty()) {
        std::cout << "Compress image failed, empty filename.\n";
        return;
    }
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Compress image failed, empty image.\n";
        return;
    }
    // 设置 JPEG 压缩参数
    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(quality);  // 质量参数，范围0-100，100为无损
    // 使用 imwrite 函数保存并压缩图片
    if (!cv::imwrite(filename, my_image, compression_params)) {
        std::cout << "Could not compress the image.\n";
        return;
    }
    std::cout << "Image compressed and saved to: " << filename << " successfully.\n";
}

/*
拉普拉斯锐化（Laplacian Sharpening）
原理：拉普拉斯锐化是一种非线性锐化方法，它通过对图像的梯度进行模糊来增强图像的锐度。
公式上，拉普拉斯锐化可以表示为：
其中，$g(x,y)$ 是图像的梯度，$g(x,y) = \frac{\partial I(x,y)}{\partial x} + \frac{\partial I(x,y)}{\partial y}$。
**适用场景**： - 拉普拉斯锐化适用于需要增强图像锐度的场景。 - 它能够增强图像的细节，使图像更加清晰。 - 它能够保留图像的边缘，使图像更加平滑。
**特点**： - 增强图像的锐度。 - 保留图像的边缘。 - 能够保留图像的细节。

**拉普拉斯锐化**：适合需要增强图像锐度的场景，尤其是需要保留图像边缘的场景。
*/
void MyPicture::sharpen_image(float level) {
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Sharpen image failed, empty image.\n";
        return;
    }
    // 创建一个拉普拉斯算子的核
    cv::Mat kernel = (cv::Mat_<float>(3, 3) <<
        -level, -level, -level,
        -level, 8 * level + 1, -level,
        -level, -level, -level);

    // 创建一个临时的 Mat 对象来存储锐化后的图像
    cv::Mat sharpened_image;
    cv::filter2D(my_image, sharpened_image, my_image.depth(), kernel);

    // 确保像素值在 0 到 255 之间
    cv::Mat clipped_image;
    sharpened_image.convertTo(clipped_image, CV_8UC3, 1, 0);
    cv::min(clipped_image, 255, clipped_image);
    cv::max(clipped_image, 0, clipped_image);

    // 释放原有图片
    //release_image();

    // 将锐化后的图像与原图像混合
    my_image = my_image + level * (clipped_image - my_image);

    std::cout << "Image sharpened with level " << level << ".\n";
}

/*
双边滤波去噪（Bilateral Filter）
原理：双边滤波是一种非线性滤波方法，它不仅考虑像素的空间距离，还考虑像素的灰度相似性。
公式上，双边滤波可以表示为：
其中，$g(||x-y||)$ 是空间距离函数，$g(||I(x)-I(y)||)$ 是灰度相似性函数。
**适用场景**： - 双边滤波适用于需要保留边缘和细节的图像去噪。 - 它在处理图像时能够有效减少噪声，同时保持图像的结构和边缘，因此非常适合用于需要精确保留图像特征的应用中。
**特点**： - 保留图像的细节和边缘。 - 对于噪声较大的图像，可能会保留一些噪声。 - 可以通过调整参数来控制去噪的程度和细节的保留程度。

**双边滤波**：适合需要保留图像细节和边缘的场景，尤其是在噪声较小的情况下。
*/
void MyPicture::bilateral_filter_image(int d, double sigmaColor, double sigmaSpace) {
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Denoise image failed, empty image.\n";
        return;
    }

    cv::Mat denoised_image;
    // 使用bilateralFilter函数进行去噪
    // d: 过滤器邻域的直径
    // sigmaColor: 颜色空间的标准差
    // sigmaSpace: 坐标空间的标准差

    /*
    参数说明
    d (过滤器邻域的直径):
        范围: 通常取值为正整数，范围在 1 到 15 之间。
    调节建议:
        较小的值（如 3 或 5）会使滤波区域更小，保留更多细节。
        较大的值（如 9 或 15）会使滤波区域更大，去除更多噪声，但可能损失一些细节。

    sigmaColor (颜色空间的标准差):
        范围: 通常取值为正数，范围在 10 到 250 之间。
    调节建议:
        较小的值会使滤波只考虑颜色差异较小的像素。
        较大的值会使滤波考虑更广泛的颜色差异。

    sigmaSpace (坐标空间的标准差):
        范围: 通常取值为正数，范围在 10 到 250 之间。
    调节建议:
        较小的值会使滤波只考虑空间上很近的像素。
        较大的值会使滤波考虑更远的像素。
    */
    cv::bilateralFilter(my_image, denoised_image, d, sigmaColor, sigmaSpace);
    my_image = denoised_image;
    //std::cout << "Image denoised with d=" << d << ", sigmaColor=" << sigmaColor << ", sigmaSpace=" << sigmaSpace << ".\n";
    std::cout << "Image denoised with bilateral filter.\n";
}

/*
非局部均值去噪（Non-local Means Denoising）
**原理**： - 非局部均值去噪是一种基于图像的相似性来去噪的技术，它利用了图像中像素块之间的相似性来进行去噪。 - 该方法通过比较图像中不同位置的像素块，将相似的像素块进行加权平均，从而达到去噪的目的。
**适用场景**： - NL-Means 适用于需要去除噪声同时保持图像结构和细节的场景。 - 它特别适合处理噪声较大的图像，尤其是高斯噪声和椒盐噪声。 - NL-Means 去噪通常用于医学图像、天文图像等需要高精度去噪的领域。
**特点**： - 去噪效果好，能够去除大部分噪声。 - 对于噪声非常大的图像，NL-Means 可以更好地保留图像的结构和细节。 - 计算复杂度较高，处理时间较长。 - 可以通过调整参数来控制去噪的程度和速度。

**非局部均值去噪**：适合噪声较大的图像去噪，尤其是需要高精度去噪的场景，如医学图像处理。 在实际应用中，你可以根据图像的噪声类型和去噪需求选择合适的方法。如果需要同时使用两种方法，可以考虑先使用 NL-Means 进行去噪，然后再使用双边滤波来进一步保留细节和边缘。
*/
void MyPicture::non_local_filter_image(int h, int hForColorComponents, int templateWindowSize, int searchWindowSize) {
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Denoise image failed, empty image.\n";
        return;
    }

    cv::Mat denoised_image;
    // 使用fastNlMeansDenoisingColored函数进行去噪
    // h: 去噪阈值，较大的值可以去除更多的噪声，但也会去除细节
    // hForColorComponents: 颜色去噪阈值，处理彩色图像时使用
    // templateWindowSize: 搜索窗口大小，用于寻找与当前像素相似的像素块
    // searchWindowSize: 搜索窗口大小，用于寻找最相似的像素块

    /*
    参数说明
    h (去噪阈值):
        范围: 通常取值为正数，范围在 3 到 15 之间。
    调节建议:
        较小的值会使去噪效果较弱，但保留更多细节。
        较大的值会使去噪效果更强，但可能去除一些细节。

    hForColorComponents (颜色去噪阈值):
        范围: 通常取值为正数，范围在 3 到 15 之间。
    调节建议:
        较小的值会使颜色去噪效果较弱，但保留更多颜色细节。
        较大的值会使颜色去噪效果更强，但可能去除一些颜色细节。

    templateWindowSize (搜索窗口大小):
        范围: 通常取值为奇数，范围在 7 到 21 之间。
    调节建议:
        较小的值会使滤波只考虑较小的像素块。
        较大的值会使滤波考虑较大的像素块，去除更多噪声。

    searchWindowSize (搜索窗口大小):
        范围: 通常取值为奇数，范围在 21 到 41 之间。
    调节建议:
        较小的值会使搜索范围更小，处理速度更快。
        较大的值会使搜索范围更大，去除更多噪声，但处理速度较慢。
    */
    cv::fastNlMeansDenoisingColored(my_image, denoised_image, h, hForColorComponents, templateWindowSize, searchWindowSize);
    my_image = denoised_image;
    //std::cout << "Image denoised with h=" << h << ", hForColorComponents=" << hForColorComponents << ", templateWindowSize=" << templateWindowSize << ", searchWindowSize=" << searchWindowSize << ".\n";
    std::cout << "Image denoised with non-local mean filter.\n";
}

/*
直方图均衡化增强对比度
*/
void MyPicture::equalization_image()
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Denoise image failed, empty image.\n";
        return;
    }
    // 如果图像是彩色的，需要先转换为灰度图像
    cv::Mat grayImage;
    if (my_image.channels() == 3) {
        cvtColor(my_image, grayImage, cv::COLOR_BGR2GRAY);
    }
    else {
        grayImage = my_image.clone();
    }
    // 使用直方图均衡化增强对比度
    cv::Mat equalized_image;
    cv::equalizeHist(grayImage, equalized_image);
    // 如果原图像是彩色的，需要将均衡化后的灰度图像重新转换为彩色图像
    if (my_image.channels() == 3) {
        cv::Mat labImage;
        cvtColor(my_image, labImage, cv::COLOR_BGR2Lab);
        std::vector<cv::Mat> labChannels;
        split(labImage, labChannels);
        labChannels[0] = equalized_image;
        cv::Mat merged;
        merge(labChannels, merged);
        cvtColor(merged, my_image, cv::COLOR_Lab2BGR);
    }
    else {
        my_image = equalized_image;
    }

    //cv::cvtColor(equalized_image, my_image, cv::COLOR_GRAY2BGR);
    //my_image = equalized_image;

    std::cout << "Image quality enhanced.\n";
}

/*
使用对比度限制自适应直方图均衡化增强图像对比度。
参数说明：
    clipLimit: 对比度限制，通常范围在0到100之间。
    tileGridSize: 直方图均衡化处理的网格大小，范围在1到100之间。
范围：
    clipLimit 通常范围在2到40之间。
    tileGridSize 通常范围在4到16之间。
使用场景：
    适用于提高图像的对比度，尤其是在光照不均匀的图像中，可以增强图像的细节和清晰度。
*/
void MyPicture::clahe_image(int clipLimit, int tileGridSize)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "CLAHE image failed, empty image.\n";
        return;
    }

    // 如果图像是彩色的，需要先转换为灰度图像
    cv::Mat grayImage;
    if (my_image.channels() == 3) {
        cvtColor(my_image, grayImage, cv::COLOR_BGR2GRAY);
    }
    else {
        grayImage = my_image.clone();
    }

    // 创建CLAHE对象并进行处理
    cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(clipLimit, cv::Size(tileGridSize, tileGridSize));
    cv::Mat clahe_image;
    clahe->apply(grayImage, clahe_image);

    // 如果原图像是彩色的，需要将均衡化后的灰度图像重新转换为彩色图像
    if (my_image.channels() == 3) {
        cv::Mat labImage;
        cvtColor(my_image, labImage, cv::COLOR_BGR2Lab);
        std::vector<cv::Mat> labChannels;
        split(labImage, labChannels);
        labChannels[0] = clahe_image;
        cv::Mat merged;
        merge(labChannels, merged);
        cvtColor(merged, my_image, cv::COLOR_Lab2BGR);
    }
    else {
        my_image = clahe_image;
    }

    std::cout << "Image quality enhanced with CLAHE.\n";
}

/*
使用中值滤波对图像进行去噪。
参数说明：
    ksize: 滤波器的大小，必须是正奇数（如3, 5, 7等）。
范围：
    ksize 通常范围在1到15之间。
使用场景：
    适用于去除椒盐噪声和其他类型的噪声，同时保留图像的边缘细节。
*/
void MyPicture::median_blur_image(int ksize)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Median blur image failed, empty image.\n";
        return;
    }

    // 使用中值滤波进行去噪
    // ksize: 滤波器的大小，必须是正奇数
    cv::Mat blurred_image;
    cv::medianBlur(my_image, blurred_image, ksize);
    my_image = blurred_image;

    std::cout << "Image blurred with median blur.\n";
}

/*
使用高斯模糊对图像进行去噪。
参数说明：
    ksize: 滤波器的大小，必须是正奇数（如3, 5, 7等）。
    sigmaX: X方向的标准差，控制模糊程度。
    sigmaY: Y方向的标准差，控制模糊程度。
范围：
    ksize 通常范围在1到15之间。
    sigmaX 和 sigmaY 通常范围在0.1到5之间。
使用场景：
    适用于去除高斯噪声，同时保持图像的边缘细节。
*/
void MyPicture::gaussian_blur_image(int ksize, double sigmaX, double sigmaY)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Gaussian blur image failed, empty image.\n";
        return;
    }

    // 使用高斯模糊进行去噪
    // ksize: 滤波器的大小，必须是正奇数
    // sigmaX: X方向的标准差
    // sigmaY: Y方向的标准差
    cv::Mat blurred_image;
    cv::GaussianBlur(my_image, blurred_image, cv::Size(ksize, ksize), sigmaX, sigmaY);
    my_image = blurred_image;

    std::cout << "Image blurred with Gaussian blur.\n";
}

/*
执行不同的形态学操作，如膨胀、腐蚀、开运算、闭运算等。
参数说明：
op: 形态学操作类型，可以是以下之一：
    cv::MORPH_ERODE: 腐蚀
    cv::MORPH_DILATE: 膨胀
    cv::MORPH_OPEN: 开运算
    cv::MORPH_CLOSE: 闭运算
    cv::MORPH_GRADIENT: 边缘检测
    cv::MORPH_TOPHAT: 顶帽运算
    cv::MORPH_BLACKHAT: 底帽运算
shape: 结构元素的形状，可以是以下之一：
    cv::MORPH_RECT: 矩形
    cv::MORPH_CROSS: 十字形
    cv::MORPH_ELLIPSE: 椭圆形
size: 结构元素的大小，范围在1到100之间。
    范围：size 通常范围在1到10之间。
使用场景：
    适用于图像的去噪、边缘检测、分割等操作，特别是在需要增强或减少某些特征时。
*/
void MyPicture::morphology_operations_image(cv::MorphTypes op, cv::MorphShapes shape, int size)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Morphology operations image failed, empty image.\n";
        return;
    }

    // 参数说明
    // op: 形态学操作类型，可以是以下之一：
    //     cv::MORPH_ERODE: 腐蚀
    //     cv::MORPH_DILATE: 膨胀
    //     cv::MORPH_OPEN: 开运算
    //     cv::MORPH_CLOSE: 闭运算
    //     cv::MORPH_GRADIENT: 边缘检测
    //     cv::MORPH_TOPHAT: 顶帽运算
    //     cv::MORPH_BLACKHAT: 底帽运算
    // shape: 结构元素的形状，可以是以下之一：
    //     cv::MORPH_RECT: 矩形
    //     cv::MORPH_CROSS: 十字形
    //     cv::MORPH_ELLIPSE: 椭圆形
    // size: 结构元素的大小，范围在1到100之间
    cv::Mat element = cv::getStructuringElement(shape, cv::Size(2 * size + 1, 2 * size + 1));
    cv::Mat result_image;

    // 执行形态学操作
    if (op == cv::MORPH_ERODE) {
        cv::erode(my_image, result_image, element);
    }
    else if (op == cv::MORPH_DILATE) {
        cv::dilate(my_image, result_image, element);
    }
    else if (op == cv::MORPH_OPEN) {
        cv::morphologyEx(my_image, result_image, cv::MORPH_OPEN, element);
    }
    else if (op == cv::MORPH_CLOSE) {
        cv::morphologyEx(my_image, result_image, cv::MORPH_CLOSE, element);
    }
    else if (op == cv::MORPH_GRADIENT) {
        cv::morphologyEx(my_image, result_image, cv::MORPH_GRADIENT, element);
    }
    else if (op == cv::MORPH_TOPHAT) {
        cv::morphologyEx(my_image, result_image, cv::MORPH_TOPHAT, element);
    }
    else if (op == cv::MORPH_BLACKHAT) {
        cv::morphologyEx(my_image, result_image, cv::MORPH_BLACKHAT, element);
    }
    else {
        std::cout << "Invalid morphology operation.\n";
        return;
    }

    my_image = result_image;
    std::cout << "Morphology operations applied.\n";
}

/*
调整图像的亮度、对比度和伽玛值以进行颜色平衡。
参数说明：
    alpha: 对比度调整，1.0表示原始对比度，值越大对比度越高。
    beta: 亮度调整，0表示原始亮度，正值增加亮度，负值减少亮度。
    gamma: 伽玛值调整，1.0表示原始亮度，值越大亮度越高。
范围：
    alpha 通常范围在0.1到3.0之间。
    beta 通常范围在-100到100之间。
    gamma 通常范围在0.1到3.0之间。
使用场景：
    适用于调整图像的整体亮度和对比度，使其更符合视觉需求。
*/
void MyPicture::color_balance_image(double alpha, double beta, double gamma)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Color balance image failed, empty image.\n";
        return;
    }

    // 参数说明
    // alpha: 对比度调整，1.0表示原始对比度，值越大对比度越高，通常范围在0.1到3.0之间
    // beta: 亮度调整，0表示原始亮度，正值增加亮度，负值减少亮度，通常范围在-100到100之间
    // gamma: 伽玛值调整，1.0表示原始亮度，值越大亮度越高，通常范围在0.1到3.0之间
    my_image.convertTo(my_image, -1, alpha, beta);

    // 调整 gamma 值
    cv::Mat lut(1, 256, CV_8UC1);
    for (int i = 0; i < 256; i++) {
        lut.at<uchar>(i) = cv::saturate_cast<uchar>(pow((float)(i / 255.0), gamma) * 255.0);
    }
    cv::LUT(my_image, lut, my_image);

    std::cout << "Color balance adjusted.\n";
}

/*
使用阈值化方法对图像进行分割。
使用场景：
    适用于简单的图像分割，通过阈值化方法将图像分为前景和背景。
*/
void MyPicture::segment_image()
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Image segmentation failed, empty image.\n";
        return;
    }

    // 转换为灰度图像
    cv::Mat grayImage;
    cvtColor(my_image, grayImage, cv::COLOR_BGR2GRAY);

    // 使用阈值化进行分割
    // 这里使用简单的阈值化方法，可以根据需要调整阈值
    cv::Mat thresholded_image;
    int threshold_value = 128;
    cv::threshold(grayImage, thresholded_image, threshold_value, 255, cv::THRESH_BINARY);
    // 也可以使用 Otsu 阈值化方法
    // cv::threshold(grayImage, thresholded_image, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);

    my_image = thresholded_image;
    std::cout << "Image segmented with thresholding.\n";
}

/*
使用Canny边缘检测器检测图像中的边缘。
参数说明：
    threshold1: 第一个阈值，用于边缘链接。
    threshold2: 第二个阈值，用于边缘检测。
范围：
    threshold1 和 threshold2 通常范围在0到255之间。
使用场景：
    适用于检测图像中的边缘，常用于图像分析和目标检测。
*/
void MyPicture::edge_detection_canny_image(int threshold1, int threshold2)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Edge detection failed, empty image.\n";
        return;
    }

    // 转换为灰度图像
    cv::Mat grayImage;
    cvtColor(my_image, grayImage, cv::COLOR_BGR2GRAY);

    // 使用Canny边缘检测器
    // 参数说明
    // threshold1: 第一个阈值，通常范围在0到255之间
    // threshold2: 第二个阈值，通常范围在0到255之间
    cv::Mat edges;
    cv::Canny(grayImage, edges, threshold1, threshold2);

    // 将边缘图像转换为彩色图像以便显示
    cv::Mat colorEdges;
    cv::cvtColor(edges, colorEdges, cv::COLOR_GRAY2BGR);

    my_image = colorEdges;
    std::cout << "Edge detection with Canny completed.\n";
}

/*
使用图像修复算法修复图像中的损坏部分。
参数说明：
mask: 掩码图像，白色区域表示需要修复的部分，黑色区域表示不需要修复的部分。
inpaintRadius: 修复半径，控制修复区域的大小。
method: 修复方法，可以是以下之一：
    cv::INPAINT_NS: Navier-Stokes 方法
    cv::INPAINT_TELEA: Telea 方法
范围：
    inpaintRadius 通常范围在1到50之间。
使用场景：
    适用于修复图像中的损坏部分或遮挡区域，常用于图像修复和编辑。
*/
void MyPicture::inpaint_image(const cv::Mat& mask, int inpaintRadius, int method)
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Image inpainting failed, empty image.\n";
        return;
    }

    // 检查掩码是否为空
    if (mask.empty()) {
        std::cout << "Image inpainting failed, empty mask.\n";
        return;
    }

    // 参数说明
    // mask: 掩码图像，白色区域表示需要修复的部分，黑色区域表示不需要修复的部分
    // inpaintRadius: 修复半径，通常范围在1到50之间
    // method: 修复方法，可以是以下之一：
    //     cv::INPAINT_NS: Navier-Stokes 方法
    //     cv::INPAINT_TELEA: Telea 方法
    cv::Mat inpainted_image;
    cv::inpaint(my_image, mask, inpainted_image, inpaintRadius, method);

    my_image = inpainted_image;
    std::cout << "Image inpainted.\n";
}

/*
使用图像金字塔方法对图像进行上采样。
使用场景：
    适用于图像的上采样，增加图像的分辨率，常用于图像增强和放大。
*/
void MyPicture::pyramid_up_image()
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Pyramid up failed, empty image.\n";
        return;
    }

    // 使用图像金字塔方法对图像进行上采样
    cv::Mat pyrUp_image;
    cv::pyrUp(my_image, pyrUp_image, cv::Size(my_image.cols * 2, my_image.rows * 2));

    my_image = pyrUp_image;
    std::cout << "Image upsampled with pyramid up.\n";
}

/*
使用图像金字塔方法对图像进行下采样。
使用场景：
    适用于图像的下采样，减少图像的分辨率，常用于图像缩小和预处理。
*/
void MyPicture::pyramid_down_image()
{
    // 检查图片是否为空
    if (my_image.empty()) {
        std::cout << "Pyramid down failed, empty image.\n";
        return;
    }

    // 使用图像金字塔方法对图像进行下采样
    cv::Mat pyrDown_image;
    cv::pyrDown(my_image, pyrDown_image, cv::Size(my_image.cols / 2, my_image.rows / 2));

    my_image = pyrDown_image;
    std::cout << "Image downsampled with pyramid down.\n";
}

/*
超分辨率增强图片画质。
参数说明：
    modelPath: 模型文件路径
    modelName: 支持的模型有 edsr, espcn, fsrcnn, lapsrn
    scale: 放大倍数
*/
void MyPicture::enhance_image_quality(const std::string& modelPath,
    const std::string& modelName,
    int scale) {
    // 超分辨率增强图片画质
    // 依赖 OpenCV 的 dnn_superres 模块（无需额外安装，OpenCV 4.1.0+自带）
    if (my_image.empty()) {
        std::cout << "Enhance image quality failed, empty image.\n";
        return;
    }
    try {
        /*
        // 将图像数据从 CPU 转移到 GPU
        cv::cuda::GpuMat gpu_image;
        gpu_image.upload(my_image);

        // 创建超分辨率对象
        cv::dnn_superres::DnnSuperResImpl sr;
        // 选择模型类型与放大倍数（如 EDSR x4）
        std::string modelPath = R"(E:\EDSR_Tensorflow-master\models\EDSR_x4.pb)"; // 模型文件路径
        std::string modelName = "edsr"; // 支持的模型有 edsr, espcn, fsrcnn, lapsrn
        int scale = 4; // 放大倍数
        // 加载模型
        sr.readModel(modelPath);
        sr.setModel(modelName, scale);

        // 在 GPU 上执行超分辨率
        cv::cuda::GpuMat gpu_enhanced_image;
        sr.upsample(gpu_image, gpu_enhanced_image);

        // 将增强后的图像数据从 GPU 转移到 CPU
        gpu_enhanced_image.download(my_image);

        std::cout << "Image enhanced by super resolution (EDSR x" << scale << ").\n";
        */

        // 创建超分辨率对象
        cv::dnn_superres::DnnSuperResImpl sr;
        // 选择模型类型与放大倍数（如 EDSR x2）
        //std::string modelPath = R"(C:\Users\Administrator\Desktop\C++学习录\C++study15_openCV\models\FSRCNN\FSRCNN_x4.pb)"; // 模型文件路径
        //std::string modelName = "fsrcnn"; // 支持的模型有 edsr, espcn, fsrcnn, lapsrn
        //int scale = 4; // 放大倍数

        // 加载模型
        sr.readModel(modelPath);
        sr.setModel(modelName, scale);
        // 执行超分辨率 CPU 版本
        cv::Mat result;
        sr.upsample(my_image, result);
        release_image();
        my_image = result;

        std::cout << "Image enhanced by super resolution (" << modelName << " x" << scale << ").\n";

    }
    catch (const std::exception& e) {
        std::cout << "Super resolution failed: " << e.what() << std::endl;
    }
}

void MyPicture::print_image_info()
{
    if (my_image.empty()) {
        std::cout << "Print image info failed, empty image.\n";
        return;
    }
    // 打印图片信息
    std::cout << "Image size: " << my_image.size() << std::endl;
    std::cout << "Image channels: " << my_image.channels() << std::endl;
    std::cout << "Image depth: " << my_image.depth() << std::endl;
    std::cout << "Image type: " << my_image.type() << std::endl;
}

int MyPicture::get_image_width() const
{
    return my_image.cols; // 宽度
}

int MyPicture::get_image_height() const
{
    return my_image.rows; // 高度
}

cv::Mat MyPicture::get_image() const
{
    return my_image;
}

void MyPicture::show(const std::string& window_name)
{
    if (my_image.empty()) {
        std::cout << "Show image failed, empty image.\n";
        return;
    }
    // 创建一个窗口
    cv::namedWindow(window_name, cv::WINDOW_NORMAL);

    // 在窗口中显示图片
    cv::imshow(window_name, my_image);
}

void MyPicture::show_input_image(const std::string& window_name, cv::Mat& image)
{
    // 创建一个窗口
    cv::namedWindow(window_name, cv::WINDOW_NORMAL);

    // 在窗口中显示图片
    cv::imshow(window_name, image);
}
